
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <cassert>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

using namespace std;

// 定义创建子进程的个数
const int num = 5;

vector<task_t> tasks;

// 多个管道的管理也是先描述再组织
// 先描述
class channel
{
public:
  channel(int cmdfd, pid_t slaverid, string slavername)
      : _cmdfd(cmdfd), _slaverid(slaverid), _slavername(slavername)
  {
  }

public:
  int _cmdfd;         // 发送任务的文件描述符
  pid_t _slaverid;    // 子进程的id
  string _slavername; // 子进程的名字
};
// 子进程执行任务
void slaver()
{
  while (true)
  {
    int cmdcode = 0;

    ssize_t n = read(0, &cmdcode, sizeof(int));
    if (n == sizeof(int))
    {
      cout << "slaver say@ " << getpid() << " get a command: " << "cmdcode: " << cmdcode << endl;
      if (cmdcode >= 0 && cmdcode < tasks.size())
        tasks[cmdcode]();
    }
    if (n == 0)
      break;
    // sleep(1);
  }
}

// 1. 初始化
void InitProcessPool(vector<channel> *channels)
{

  for (int i = 0; i < num; i++)
  {
    int pipefd[2];
    int n = pipe(pipefd);
    assert(!n); // pipe 成功返回0， 失败返回-1，这里失败直接断言报错
    (void)n;

    pid_t id = fork();
    if (id < 0)
      return;
    if (id == 0)
    {
      // child
      //  子进程读, 关闭写端
      close(pipefd[1]);
      // 子进程执行任务
      // slaver(pipefd[0]);
      dup2(pipefd[0], 0);
      slaver();

      exit(0);
    }
    // father
    // 父进程写， 关闭读端
    close(pipefd[0]);

    string name = "process-" + to_string(i);
    channels->push_back(channel(pipefd[1], id, name));
  }
}

void Debug(const vector<channel> &channels)
{
  // test
  for (auto &c : channels)
  {
    cout << "发送任务的文件描述符: " << c._cmdfd << "子进程id: " << c._slaverid << "子进程名字: " << c._slavername << endl;
  }
}

void ctrlSlaver(const vector<channel> &channels)
{
  int cnt = 5;
  while (cnt--)
  {
    // 1. 选择任务
    int cmdcode = rand() % tasks.size();
    // 2. 选择进程
    int processpos = rand() % channels.size();
    cout << "father say@" << "cmdcode:" << cmdcode << " already sendto" << channels[processpos]._slaverid << "process name: " << channels[processpos]._slavername << endl;
    // 3. 发布任务
    write(channels[processpos]._cmdfd, &cmdcode, sizeof(cmdcode));
    sleep(1);
  }

  cout << "father wait finished" << endl;
}

void QuitProcess(const vector<channel> &channels)
{
  for (const auto &c : channels)
  {
    close(c._cmdfd);
  }
  for (const auto &c : channels)
  {
    waitpid(c._slaverid, nullptr, 0);
  }
  sleep(5);
}
int main()
{
  Loadtask(&tasks);

  // 种一个随机数的种子
  srand(time(nullptr) ^ 1024 ^ num);
  // 再组织
  vector<channel> channels;
  // 1. 初始化
  InitProcessPool(&channels);

  // test 检查初始化是否成功
  Debug(channels);

  // 2. 对子进程的控制
  ctrlSlaver(channels);

  // 3. 清理工作
  QuitProcess(channels);

  return 0;
}